package com.ruoyi.business.common;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.ruoyi.bizsys.domain.*;
import com.ruoyi.bizsys.service.*;
import com.ruoyi.bizsys.utils.BizConstants;
import com.ruoyi.bizsys.vo.MonnifyReservedAccount;
import com.ruoyi.business.domain.BusinessMarketUser;
import com.ruoyi.business.domain.CustomerVO;
import com.ruoyi.business.mapper.BCreditAccountMapper;
import com.ruoyi.business.service.IAppBankAccountService;
import com.ruoyi.business.service.IBusinessService;
import com.ruoyi.business.service.IMonnifyService;
import com.ruoyi.business.service.RestTemplateService;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.RiskConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.UserTagEnum;
import com.ruoyi.common.utils.EmailUtils;
import com.ruoyi.common.utils.FeishuUtils;
import com.ruoyi.common.utils.Func;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.vo.EmailVo;
import com.ruoyi.sms.domain.SmsSendData;
import com.ruoyi.sms.service.ISmsService;
import com.ruoyi.system.service.ISysConfigService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author cyh
 */
@Slf4j
@Component
@AllArgsConstructor
public class AsyncService {

    private RedisCache redisCache;

    private ISmsService smsService;

    private IAppUserMarkService appUserMarkService;

    //远程调用url地址
    @Autowired
    private RestTemplateService restTemplateService;

    private ICreditAccountService creditAccountService;

    private IBusinessService businessService;

    public static final String AUTOMATIC_RAISE_LOCK = "RaiseLimitLock:";

    private IRealNameAuthService realNameAuthService;

    private IAppBankAccountService appBankAccountService;

    private BCreditAccountMapper creditAccountMapper;

    private IMonnifyService monnifyService;

    @Autowired
    private ICrsUserService crsUserService;

    @Autowired
    private IAppUserService appUserService;

    @Autowired
    private ISysConfigService sysConfigService;

    @Autowired
    private IAppsflyerChannelService appsflyerChannelService;

    @Async("threadPoolTaskExecutor")
    public void sendCommonEmail(EmailVo emailVo) {
        EmailUtils.sendCommonEmail(emailVo);
    }

    @Async("threadPoolTaskExecutor")
    public void sendCustomizeEmail(EmailVo emailVo) {
        EmailUtils.sendCustomizeEmail(emailVo);
    }

    @Async("threadPoolTaskExecutor")
    public void sendFeishu(String name, String title, JSONObject content) {
        log.info("开始发送飞书");
        FeishuUtils.sendFeishu(name, title, content);
    }

    @Async("threadPoolTaskExecutor")
    public void sendSms(SmsSendData smsData) {
        smsService.sendSms(smsData);
    }

    @Async("threadPoolTaskExecutor")
    public void apdUserTag(AppUserMark userMark, UserTagEnum tagEnum) {
        appUserMarkService.apdUserTag(userMark, tagEnum);
    }

    /**
     * 异步发送VA 短信
     */
    @Async("threadPoolTaskExecutor")
    public void sendVaSms(String userId, MonnifyReservedAccount monnifyReservedAccount, BigDecimal miniPay) {
        JSONObject smsParam = new JSONObject();
        RealNameAuth realNameAuth = getRealNameAuth(userId);
        smsParam.put("last_name", realNameAuth.getLastName());
        smsParam.put("mini_pay", miniPay.setScale(2, BigDecimal.ROUND_UP));
        smsParam.put("VA", monnifyReservedAccount.getAccountNumber());
        SmsSendData smsData = SmsSendData.builder().smsType(BizConstants.SMS_TYPE_LOANEXTENSION_PYMT).noticeType(BizConstants.SMS_NOTICE_TYPE_NOTICE).countryCode("+234").phoneNumber(realNameAuth.getPhoneNumber()).smsParam(smsParam).build();
        smsService.sendSms(smsData);
    }

    /**
     * 异步发送减免成功 短信
     */
    @Async("threadPoolTaskExecutor")
    public void sendExemptionSms(String userId, BigDecimal collectAmt, BigDecimal exemptionAmt) {
        JSONObject smsParam = new JSONObject();
        String phone = appUserService.selectAppUserByPhone(userId);
        smsParam.put("CollectAmt", collectAmt.setScale(0, BigDecimal.ROUND_UP));//剩余应还金额
        smsParam.put("ExemptionAmt", exemptionAmt.setScale(0, BigDecimal.ROUND_DOWN));//减免金额
        smsParam.put("RemainingAmt", collectAmt.subtract(exemptionAmt).setScale(0, BigDecimal.ROUND_UP));//剩余应还金额-减免金额
        SmsSendData smsData = SmsSendData.builder().smsType(BizConstants.SMS_TYPE_COLL_RPY_XMPT).noticeType(BizConstants.SMS_NOTICE_TYPE_NOTICE).countryCode("+234").phoneNumber(phone).smsParam(smsParam).build();
        smsService.sendSms(smsData);
    }

    /**
     * 放款延迟致歉短信
     */
    @Async("threadPoolTaskExecutor")
    public void loanDelay(String custNo,BigDecimal amount) {
        JSONObject smsParam = new JSONObject();
        RealNameAuth realNameAuth = realNameAuthService.selectRealNameAuthByCustNo(custNo);
        smsParam.put("lastName", realNameAuth.getLastName());
        smsParam.put("amount", amount.setScale(2, BigDecimal.ROUND_UP));
        SmsSendData smsData = SmsSendData.builder().smsType(BizConstants.SMS_TYPE_TEMO_WDRW_FAIL_SRY).noticeType(BizConstants.SMS_NOTICE_TYPE_NOTICE).countryCode("+234").phoneNumber(realNameAuth.getPhoneNumber()).smsParam(smsParam).build();
        smsService.sendSms(smsData);
    }


    /**
     * 提现成功致歉放款延迟短信
     */
    @Async("threadPoolTaskExecutor")
    public void withdrawLoanDelay(String custNo ,BigDecimal loanAmt) {
        JSONObject smsParam = new JSONObject();
        RealNameAuth realNameAuth = realNameAuthService.selectRealNameAuthByCustNo(custNo);
        smsParam.put("lastName", realNameAuth.getLastName());
        smsParam.put("loanAmt", loanAmt.setScale(2, BigDecimal.ROUND_UP));
        SmsSendData smsData = SmsSendData.builder().smsType(BizConstants.SMS_TYPE_MAIN_ISFCFNDS_DISBSUCC).noticeType(BizConstants.SMS_NOTICE_TYPE_NOTICE).countryCode("+234").phoneNumber(realNameAuth.getPhoneNumber()).smsParam(smsParam).build();
        smsService.sendSms(smsData);
    }

    protected RealNameAuth getRealNameAuth(String userId) {
        RealNameAuth auth = new RealNameAuth();
        auth.setUserId(userId);
        auth.setState(BizConstants.BIZ_STATUS_1);
        List<RealNameAuth> realNameAuthList = realNameAuthService.selectRealNameAuthList(auth);
        RealNameAuth realNameAuth = realNameAuthList.get(0);
        return realNameAuth;
    }

    /**
     * 授信成功
     */
    @Async("threadPoolTaskExecutor")
    public void sendCreditPassSms(CreditApply apply, AppUser appUser, BigDecimal creditLine, BigDecimal channelLine, AppUser validInviter) {
        JSONObject smsParam = new JSONObject();
        //判断当前用户是否满足 0利息/折扣利息 产品
        String smsType = null;
        List<ProductInfo> productInfo = creditAccountService.selectCreditAccountProduct(apply.getCustNo());
        productInfo.stream().sorted(Comparator.comparing(obj -> obj.getTags().contains("-1") ? 1 : 0)).collect(Collectors.toList());
        if (productInfo.size() > 0) {
            for (int i = 0; i < productInfo.size(); i++) {
                String params = productInfo.get(i).getTags();
                smsParam.put("last_name", getRealNameAuth(appUser.getUserUuid()).getLastName());
                smsParam.put("credit_line", String.valueOf(creditLine.setScale(2, BigDecimal.ROUND_HALF_UP)));
                smsParam.put("credit_rating", sysConfigService.selectConfigKey(productInfo.get(i).getCreditRating()));
                if (params.contains("-1")) {
                    smsParam.put("productperiod", productInfo.get(i).getPeriodNum());
                    smsParam.put("tags", "0 interest");
                } else if (params.contains("%")) {
                    smsParam.put("productperiod", productInfo.get(i).getPeriodNum());
                    BigDecimal multiply = ((productInfo.get(i).getShowInterestRate().subtract(productInfo.get(i).getInterestRate())).divide(productInfo.get(i).getShowInterestRate(), BigDecimal.ROUND_HALF_UP)).multiply(BigDecimal.valueOf(100)).setScale(0, BigDecimal.ROUND_HALF_UP);
                    smsParam.put("tags", multiply + "% interest discount");
                }
                smsType = BizConstants.SMS_TYPE_MAIN_CR_SUCC_0ORDISCINT;
                break;
            }
        } else {
            //渠道额度为0时发送无邀请人短信
            smsParam.put("lastName", getRealNameAuth(appUser.getUserUuid()).getLastName());
            smsParam.put("creditLine", String.valueOf(creditLine.setScale(2, BigDecimal.ROUND_HALF_UP)));
            smsType = BizConstants.SMS_TYPE_CREDIT_PASS;
            //渠道额度不为0时发送邀请人短信
            if (!channelLine.equals(BigDecimal.ZERO)) {
                //最终额度 - 渠道额度
                //基础额度
                smsParam.put("creditLine", String.valueOf(creditLine.subtract(channelLine).setScale(2, BigDecimal.ROUND_HALF_UP)));
                smsParam.put("inviterNickname", validInviter.getNickName());
                smsParam.put("channelQuota", String.valueOf(channelLine.setScale(2, BigDecimal.ROUND_HALF_UP)));
                smsParam.put("finalQuota", String.valueOf(creditLine.setScale(2, BigDecimal.ROUND_HALF_UP)));
                smsType = BizConstants.SMS_TYPE_INVITER_CREDIT;
            }
        }
        SmsSendData smsData = SmsSendData.builder().smsType(smsType).noticeType(BizConstants.SMS_NOTICE_TYPE_NOTICE).countryCode(appUser.getCountryCode()).phoneNumber(appUser.getPhone()).smsParam(smsParam).build();
        smsService.sendSms(smsData);
    }


    @Async("threadPoolTaskExecutor")
    public void updateAppUserMark(String userId, String type) {
        //修改用户标签
        QueryWrapper<AppUserMark> wrapper = new QueryWrapper<AppUserMark>()
                .eq("user_id", userId).last("limit 1");
        AppUserMark appUserMark = appUserMarkService.getOne(wrapper);
        switch (type) {
            case "bankAccount":
                if (Func.isNotEmpty(appUserMark) && appUserMark.getFirstTag().equals(UserTagEnum.CREDIT_APPLICATION_SUCCESS_ACCOUNT_EXISTED.getFirstTag())) {
                    appUserMark.setSecondTag(UserTagEnum.CREDIT_APPLICATION_SUCCESS_ACCOUNT_EXISTED.getSecondTag());
                    appUserMarkService.updateAppUserMark(appUserMark);
                    break;
                }
            case "custBankCard":
                if (Func.isNotEmpty(appUserMark) && appUserMark.getFirstTag().equals(UserTagEnum.LOAN_SUCCEED_BIND_CARD.getFirstTag())) {
                    appUserMark.setSecondTag(UserTagEnum.LOAN_SUCCEED_BIND_CARD.getSecondTag());
                    appUserMarkService.updateAppUserMark(appUserMark);
                    break;
                }
        }

    }

    @Async("threadPoolTaskExecutor")
    public void checkChannel(String phone,String channel) {
        AppUser user = appUserService.getOne(new QueryWrapper<AppUser>().eq("phone", phone));
        if (user != null) {
            AppUser appUser = new AppUser();
            //1.查询crs
            CrsUser crsUser = crsUserService.getOne(new QueryWrapper<CrsUser>().eq("call_phone", phone));
            if (crsUser != null) {
                appUser.setUserId(user.getUserId());
                appUser.setChannel(crsUser.getChannel());
                appUser.setStageResult(crsUser.getStageResult());
                appUserService.updateAppUser(appUser);
            } else {
                if (!(null == channel)&& !StringUtils.isEmpty(channel)) {
                    appUser.setUserId(user.getUserId());
                    appUser.setChannel(channel);
                    appUserService.updateAppUser(appUser);
                }
            }
        }
    }

    @Async("threadPoolTaskExecutor")
    public void appendAccount(String userId) {
        appBankAccountService.appendAccount(userId);
    }

    /**
     * 自动提额
     */
    @Async("threadPoolTaskExecutor")
    public void automaticRaiseLimit(String loanSerialNo, String customerNo, RuleIn ruleIn) {
        log.info("客户号{}借据{}开始自动化提额", customerNo, loanSerialNo);
        String lockKey = AUTOMATIC_RAISE_LOCK + customerNo;

        RLock lock = redisCache.lock(lockKey);
        try {
            long start = System.currentTimeMillis();
            //规则引擎
            JSONObject ruleRst = restTemplateService.riskRuleRaiseLimits(loanSerialNo, customerNo, ruleIn);

            //接收审批结果
            String result = ruleRst.getString(RiskConstants.RULE_RESULT_DEAL_TYPE_KEY);
            //更新信用评级 只在通过/拒绝的时候保存（来自需求）
            if (StringUtils.equalsAny(result, RiskConstants.RULE_RESULT_PASS, RiskConstants.RULE_RESULT_REJECT)) {
                businessService.upCreditRatingByCustNo(ruleRst.getString(RiskConstants.RULE_CREDIT_RATING), customerNo);
            }
            //不等于Accept 均失败
            if (!StringUtils.equals(result, RiskConstants.RULE_RESULT_PASS)) {
                return;
            }

            //更新授信账户,记录提额日志
            BigDecimal raiseLimit = ruleRst.getBigDecimal(RiskConstants.RULE_RAISE_PASS_ADJUST_LIMIT);
            //校验测算额度 发送短信
            int res = creditAccountService.updateCreditLine(raiseLimit, customerNo, Constants.RaiseLimit.ADJUST_TYPE_AUTOMATIC_ALLOCATION);
            if (res > 0) {
                this.sendRaiseSms(customerNo, raiseLimit);
            }
            log.info("客户号{}提额流程结束", customerNo);
            long end = System.currentTimeMillis();
            log.info("锁占用时间，耗时：" + (end - start) + " ms");
        } catch (Exception e) {
            log.error("自动化提额异常", e);
        } finally {
            lock.unlock();
        }

    }

    private void sendRaiseSms(String customerNo, BigDecimal raiseLimit) {

        log.info("客户{}开始发送提额短信,提额:{}", customerNo, raiseLimit);
        RealNameAuth realNameAuth = new RealNameAuth();
        realNameAuth.setCustNo(customerNo);
        realNameAuth = realNameAuthService.selectRealNameAuthList(realNameAuth).get(0);

        AppUser appUser = new AppUser();
        appUser.setUserUuid(realNameAuth.getUserId());
        appUser.setPhone(realNameAuth.getPhoneNumber());
        appUser.setCountryCode("+234");
        int i = smsService.sendRepaymentPassSms(customerNo, appUser);
        //未拥有延期产品
        if (i == 0) {
            CustomerVO customer = businessService.getCustomerInfo(customerNo);

            JSONObject smsParam = new JSONObject();
            smsParam.put("last_name", customer.getLastName());
            //提额额度
            smsParam.put("limit_adjust", raiseLimit);
            //提额后额度
            CreditAccount account = creditAccountMapper.findInCustNos(customerNo).get(0);
            smsParam.put("credit_line", account.getCreditLine());

            SmsSendData smsData = SmsSendData.builder().noticeType(BizConstants.SMS_NOTICE_TYPE_NOTICE).countryCode(customer.getCountryCode()).phoneNumber(customer.getPhone()).smsParam(smsParam).build();
            //历史用户 || 提额=测算
            if (customer.getPreLine() == null) {
                smsData.setSmsType(BizConstants.SMS_TYPE_RAISE_LIMIT_END_EQUAL_PRE);
            } else {
                int configNum = Integer.parseInt(sysConfigService.selectConfigByKey("raise_min_num"));
                //小于500不发短信
                if (raiseLimit.compareTo(new BigDecimal(configNum)) < 0) {
                    return;
                }
                int compareResult = raiseLimit.compareTo(customer.getPreLine());
                //提额<测算
                if (compareResult < 0) {
                    smsData.setSmsType(BizConstants.SMS_TYPE_RAISE_LIMIT_END_LESS_PRE);
                }
                //提额=测算
                if (compareResult == 0) {
                    smsData.setSmsType(BizConstants.SMS_TYPE_RAISE_LIMIT_END_EQUAL_PRE);
                }
                //提额>测算
                if (compareResult > 0) {
                    smsData.setSmsType(BizConstants.SMS_TYPE_RAISE_LIMIT_END_GREATER_PRE);
                }
            }
            log.info("客户{}发送提额短信,提额短信内容:{}", customerNo, smsData);
            smsService.sendSms(smsData);
        }
    }

    @Async("threadPoolTaskExecutor")
    public void updateMarketUserInfo(BusinessMarketUser marketUser) {
        businessService.loanOrCreditUpdateMarketUserInfo(marketUser);
        log.info("----------loan order or credit apply update marketUser------ ");
    }

    @Async("threadPoolTaskExecutor")
    public void asyncGenerateMonnifyReservedAccount(String custNo, String bankCode) {
        log.info("客户号 {} 银行编码 {} 异步生成预留账户开始", custNo, bankCode);
        monnifyService.generateMonnifyReservedAccount(custNo, bankCode);
        log.info("客户号 {} 银行编码 {} 异步生成预留账户结束", custNo, bankCode);
    }
}
